// messages.cpp
// Customizer
// Protea Customizer / Business Logic for managing messages
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Please send correspondence to:
//
// theproteaproject@gmail.com
//

#include "customizer.h"

//////////////////////////////////////////////
//
// Transactions
//
//////////////////////////////////////////////

//@ SEC 2

//
//@ CHA AddMessage
//@ COD AddMessage
//@ NUM 190
//@ TAB MSG_DEFN Write 
//
//@ GEN AddMessage will write a record to the MSG_DEFN table
//
TRANSACTION_CODE( AddMessage ) {
	//@ GRS Start the transaction
	START_TXN( AddMessage );
		//@ Start database transaction
		START_DB_TXN();
			AddMessageInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();

		//@ Send back result buffer
		App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};






//
//@ CHA ChgMessage
//@ COD ChgMessage
//@ NUM 190
//@ TAB MSG_DEFN Write 
//
//@ GEN AddMessage will write a record to the MSG_DEFN table
//
TRANSACTION_CODE( ChgMessage ) {
	XCBuffer* TransBuf = NULL;
	XCBuffer* Old_Buffer = NULL;
	XCBuffer* Old_Master_Buffer = NULL;
	XCBuffer* master = NULL;
	XCStatedTxn* Save_Txn = NULL;

	//@ GRS Start the transaction
	START_TXN( ChgMessage );

		//@ Create message defn buffer
		TransBuf = App->CreateBuffer( FMT_MSG_DEFN, true );

		//@ Create the message master buffer
		master = App->CreateBuffer( FMT_MSG_MASTER, true );

		//@ Check if review only
		if (txnvars.phase == PHASE_UPDATE) {
			//@ Find the phased transaction
			Save_Txn = App->StatedTxnList->Find( txnvars.id );
			if (!Save_Txn) {
				//@ Set the transaction phase to REVIEW
				txnvars.result->SetPhase( PHASE_REVIEW );

				//@ ERR C (-6000) Transaction timed out
				txnvars.Errors->Add( ERR_TXN_TIME_OUT, SEV_CRITICAL, 0 );
			};
		};

		START_DB_TXN();
			//@ If the transaction phase is REVIEW
			if (txnvars.phase == PHASE_REVIEW) {
				//@ GRS

				//@ Move screen info to transaction buffer
				TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors, true );
				master->MoveCorresponding( txnvars.buffer, txnvars.Errors, true );

				//@ Check for errors
				txnvars.Errors->Check();

				//@ SUB MessageDefnValidate to validate input data
				MessageDefnVerify( TransBuf, master, VERIFY_REVIEW, &txnvars, false );

				//@ Clear the output buffer
				txnvars.buffer->Clear();

				//@ Move corresponding values from the transaction buffer to the output buffer
				txnvars.buffer->MoveCorresponding( TransBuf, txnvars.Errors );
				txnvars.buffer->MoveCorresponding( master, txnvars.Errors );

				//@ Save the transaction by the current transaction ID.  Save the transaction buffer
				App->StatedTxnList->Add( txnvars.id, 2, TransBuf, master );
				TransBuf = NULL;
				master = NULL;

				//@ Set the transaction phase to UPDATE
				txnvars.result->SetPhase( PHASE_UPDATE );

				//@ GRE
			} else {
				//@ Otherwise, the transaction phase is UPDATE
				//@ GRS

				//@ Get the saved transaction buffer
				Old_Buffer = Save_Txn->buflist->GetBuffer(0);
				Old_Master_Buffer = Save_Txn->buflist->GetBuffer(1);

				//@ Load the old record
				TransBuf->MoveCorresponding( Old_Buffer, txnvars.Errors );
				master->MoveCorresponding( Old_Master_Buffer, txnvars.Errors );
				MessageDefnRetrieve( TransBuf, &txnvars );
				MessageMasterRetrieve( master, &txnvars );

				//@ Check for errors
				txnvars.Errors->Check();

				if ((Old_Buffer && TransBuf->MarkChanges( Old_Buffer )) || (Old_Master_Buffer && master->MarkChanges( Old_Master_Buffer ))) {
					//@ Set the transaction phase to REVIEW
					txnvars.result->SetPhase( PHASE_REVIEW );

					//@ Cleanup the saved transaction buffer
					App->StatedTxnList->Remove( txnvars.id );

					//@ ERR C (-6001) Original data modified by another party.  Restart txn.
					txnvars.Errors->Add( ERR_TXN_RETRY, SEV_CRITICAL, 0 );
				};

				//@ Move in screen values
				TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors, true );

				//@ SUB MessageDefnVerify to validate input data
				MessageDefnVerify( TransBuf, master, VERIFY_CHANGE, &txnvars, false, Old_Buffer );
				master->MoveCorresponding( txnvars.buffer, txnvars.Errors, true );

				//@ SUB MessageDefnChange to change message record
				MessageDefnChange( TransBuf, Old_Buffer, &txnvars );
				MessageMasterChange( master, Old_Master_Buffer, &txnvars );

				//@ Move corresponding values from the transaction buffer to the output buffer
				txnvars.buffer->MoveCorresponding( TransBuf, txnvars.Errors );
				txnvars.buffer->MoveCorresponding( master, txnvars.Errors );

				//@ Release the old saved buffer
				Save_Txn->buflist->Clear();
				Old_Buffer->Release();
				Old_Master_Buffer->Release();

				//@ Move the results to the new save buffer
				Save_Txn->buflist->Add( 2, TransBuf, master );
				TransBuf = NULL;
				master = NULL;

				//@ GRE
			};
		END_DB_TXN();

		LOG_TRANSACTION();

		//@ Send back result buffer
		App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

	CLEANUP_TXN();
		App->CleanupObjects( 2, &TransBuf, &master );
	END_TXN();
	//@ GRE End the transaction
};




//
//@ CHA DeleteMessage
//@ COD DeleteMessage
//@ NUM 190
//@ TAB MSG_DEFN Write 
//
//@ GEN DelMessage will delete a record in the MSG_DEFN table
//
TRANSACTION_CODE( DelMessage ) {
	//@ GRS Start the transaction
	START_TXN( DelMessage );
		//@ Start database transaction
		START_DB_TXN();
			DelMessageInternal( &txnvars, false );
		END_DB_TXN();

		LOG_TRANSACTION();
	CLEANUP_TXN();
	END_TXN();
	//@ GRE End the transaction
};




//
//@ CHA RevMessages
//@ COD RevMessages
//@ NUM 190
//@ TAB MSG_DEFN Read 
//
//@ GEN RevMessages will review MSG_DEFN records
//
TRANSACTION_CODE( RevMessages ) {

	XCBuffer* TransBuf = NULL;
	XCBuffer* countbuf = NULL;
	XCBuffer* detail = NULL;
	XCBuffer* master = NULL;
	XCField* deleteme = NULL;
	XCDBStatement* stmt = NULL;

	//@ GRS Start the transaction
	START_TXN( RevMessages );

		//@ Create MSG_DEFN buffer
		TransBuf = App->CreateBuffer( FMT_MSG_DEFN, false );

		TransBuf->MoveCorresponding( txnvars.buffer, txnvars.Errors );
		TransBuf->Validate();

		master = App->CreateBuffer( FMT_MSG_MASTER, false );
		master->MoveCorresponding( txnvars.buffer, txnvars.Errors );

		//@ Start database transaction
		START_DB_TXN();
			XCSQLGen* query = txnvars.query;
			txnvars.buffer->DebugDump();
			TransBuf->DebugDump();

			//@ Determine if message number is already in use
			XCCompare comp[ 6 ];
			XCField* fieldlist[ 7 ];

			// Prepare the selection criteria
			int fcount = 0;
			XCField* tempfield;

			fieldlist[fcount++] = TransBuf->GetField( FLD_APPL_NBR );

			// Message numbers
			tempfield = txnvars.buffer->GetField( FLD_SEARCH_MIN );
			if (tempfield && !tempfield->IsBlank()) {
				XCField* tempfield2 = txnvars.buffer->GetField( FLD_SEARCH_MAX );
				if (tempfield2 && !tempfield2->IsBlank()) {
					comp[ fcount ].comparison = cmp_greaterthanequals;
					TransBuf->MoveUnlikeField( FLD_MSG_NBR, txnvars.buffer, FLD_SEARCH_MIN );
					fieldlist[fcount++] = TransBuf->GetField( FLD_MSG_NBR );

					comp[ fcount ].comparison = cmp_lessthanequals;
					deleteme = TransBuf->GetField( FLD_MSG_NBR )->Clone();
					deleteme->MoveField( tempfield2 );
					fieldlist[fcount++] = deleteme;
				};
			};

			// Search on message name
			tempfield = txnvars.buffer->GetField( FLD_SEARCH_TEXT );
			if (tempfield && !tempfield->IsBlank()) {
				comp[ fcount ].comparison = cmp_like;
				TransBuf->MoveUnlikeField( FLD_MSG_NAME, txnvars.buffer, FLD_SEARCH_TEXT );
				fieldlist[fcount++] = TransBuf->GetField( FLD_MSG_NAME );
			};
			
			// Search on message text
			tempfield = txnvars.buffer->GetField( FLD_SEARCH_VALUE );
			if (tempfield && !tempfield->IsBlank()) {
				comp[ fcount ].comparison = cmp_like;
				TransBuf->MoveUnlikeField( FLD_MSG_TEXT, txnvars.buffer, FLD_SEARCH_VALUE );
				fieldlist[fcount++] = TransBuf->GetField( FLD_MSG_TEXT );
			};

			tempfield = txnvars.buffer->GetField( FLD_LANG_ID );
			if (tempfield && !tempfield->IsBlank()) {
				TransBuf->MoveField( txnvars.buffer, FLD_LANG_ID );
				fieldlist[fcount++] = TransBuf->GetField( FLD_LANG_ID );
			};

			fieldlist[ fcount ] = NULL;

			XCOrder order;

			// Determine if we are doing a count only
			XCField* temp = txnvars.buffer->GetField( FLD_RESULT_COUNT );
			bool count_only = false;
			if (temp && temp->GetLong( true ) == 1)
				count_only = true;

			// Create the SQL statement
			if (count_only) {
				countbuf = query->MakeCOUNT( TransBuf );
			} else {
				query->MakeSELECT( TransBuf );
			};

			XCJoin join;
			join.buffer = master;
			join.type = join_inner;
			join.predicate = new XCCompare[2];
			join.predicate_count = 2;
			join.predicate[0].field = TransBuf->GetField( FLD_APPL_NBR );
			join.predicate[0].field2 = master->GetField( FLD_APPL_NBR );
			join.predicate[1].field = TransBuf->GetField( FLD_MSG_NBR );
			join.predicate[1].field2 = master->GetField( FLD_MSG_NBR );

			query->AddJOIN( &join, 0 );
			query->AddWHERE( fieldlist, comp );

			// DB2 doesn't like ORDERBY on SELECT COUNT
			if (!count_only) {
				order.format = TransBuf;
				query->AddORDERBY( FLD_MSG_NBR, &order );
			};
			stmt = txnvars.dbtxn->ExecuteSQL( query );

			if (count_only) {
				temp->MoveField( countbuf->GetFieldByIndex(0) );
				App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );
			} else {
				App->TransResponse( txnvars.result, txnvars.buffer, TRANS_HEADER_TYPE );

				//@ Look through all matching records
				if (!stmt->Eof()) {
					int child = txnvars.buffer->GetChildFormat();
					if (child) {
						detail = App->CreateBuffer( child, false );

						// Send all other data packets
						while (!stmt->Eof()) {
							detail->Clear();
							detail->MoveCorresponding( TransBuf, txnvars.Errors, true );
							detail->MoveCorresponding( master, txnvars.Errors, true );
	//						LookupNameFromNumber( &txnvars, TransBuf, detail, FLD_FIELD_NUMBER, FLD_FIELD_NAME, FMT_FIELD_DESCRIPTOR );
							txnvars.Errors->Check();

							App->TransResponse( txnvars.result, detail, TRANS_DETAIL_TYPE );
							stmt->MoveNext();
						};
					};
				};
			};

		END_DB_TXN();

	CLEANUP_TXN();
		App->CleanupObjects( 6, &stmt, &deleteme, &TransBuf, &countbuf, &detail, &master );
	END_TXN();
	//@ GRE End the transaction
};
